package bola
{
	// ========================================================================
	import com.HitTest;
	
	import flash.display.DisplayObject;
	import flash.display.Sprite;
	import flash.geom.Point;
	
	import kapi.API;
	import kapi.mvc.Enfocable;
	import kapi.mvc.Graficable;
	import kapi.utiles.Evento;
	
	import nivel.Mundo;
	// ========================================================================

	public class Bola implements Enfocable
	{
		// ====================================================================
		private var ACELERACION_NORMAL:Number = 0.01
		private var ACELERACION_GRAVITATORIA:Number = 0.01
		private var ACELERACION_NULA:Number = 0

		private var _posicion:Point
		private var _aceleracionX:Number
		private var _aceleracionY:Number
		private var _velocidad:Point	
		private var _mundo:Mundo

		// VER COMO SEPARAR ESTO EN UNA VISTA
		private var _grafico:Sprite

		private var _alPosicionar:Evento
		private var _antesDeActualizar:Evento
		private var _despuesDeActualizar:Evento
		// ====================================================================

		// ====================================================================
		// CONSTRUCTOR
		// ====================================================================

		// --------------------------------------------------------------------
		public function Bola()
		{
			inicializar()
			crearEventos()
		}
		
		// ====================================================================
		// PROPERTIES
		// ====================================================================

		// --------------------------------------------------------------------
		public function get posicion():Point {
			return _posicion
		}
		// --------------------------------------------------------------------
		public function get mundo():Mundo {
			return _mundo
		}
		// --------------------------------------------------------------------
		public function get grafico():DisplayObject {
			return _grafico
		}
		// --------------------------------------------------------------------
		public function get velocidad():Point {
			return _velocidad 
		}
		// --------------------------------------------------------------------
		public function get alCambiarLaPosicion():Evento {
			return _alPosicionar
		}
		// --------------------------------------------------------------------
		public function get alPosicionar():Evento {
			return _alPosicionar
		}
		// --------------------------------------------------------------------
		public function get antesDeActualizar():Evento {
			return _antesDeActualizar
		}
		// --------------------------------------------------------------------
		public function get despuesDeActualizar():Evento {
			return _despuesDeActualizar
		}

		// ====================================================================
		// FUNCIONES
		// ====================================================================

		// --------------------------------------------------------------------
		private function inicializar():void
		{
			_posicion = new Point(0, 0)
			_aceleracionX = 0
			_aceleracionY = 0
			_grafico = new API.recursos['mcBola']()
			API.reloj.enCadaTick.escuchar(actualizar)
		}
		// --------------------------------------------------------------------
		private function crearEventos():void
		{
			_alPosicionar = new Evento()
			_antesDeActualizar = new Evento()
			_despuesDeActualizar = new Evento()
		}

		// --------------------------------------------------------------------
		public function incluirEn(mundo:Mundo):void
		{
			_mundo = mundo
			_mundo.agregar(this)
			_mundo.moverSegun(this)
		}

		/**
		 *	Como mover la bola
		 * 
		 *		1. intentar mover a la izquierda (o derecha)
		 * 		2. si no me pude mover a la izquierda por colision:
		 * 			2a. intentar mover hacia arriba un poquito (si continuo 
		 * 				colisionando no me muevo a la izquierda (o derecha)
		 * 		3. intentar caer un poquito
		 * 
		 * 	TENER UNA SOLA VARIABLE "VELOCIDAD" (vector) e ir modificandola
		 * 	con cada movimiento, en la actualizacion mover la bola segun el
		 * 	valor actual de esa velocidad. ( los movimientos son aceleraciones
		 * 	que modifican la norma y el angulo del vector.
		 * 
		 */
		// --------------------------------------------------------------------
		public function posicionar(posicion:Point, notificar:Boolean = true):void
		{
			if (!posicion)
				throw new Error('No se puede posicionar en una posicion nula')

			_posicion = posicion
			posicionarGrafico(_posicion)
			if (notificar)
				_alPosicionar.notificar(_posicion)
		}
		// --------------------------------------------------------------------
		private function posicionarGrafico(posicion:Point):void
		{
			_grafico.rotation += (posicion.x - _grafico.x) * 2
			_grafico.x = posicion.x
			_grafico.y = posicion.y
		}

		// --------------------------------------------------------------------
		public function desplazarHorizontalmente(direccion:Point):void {
			_aceleracionX = ACELERACION_NORMAL * direccion.x
		}
		// --------------------------------------------------------------------
		public function dejarDeDesplazarHorizontalmente():void {
			_aceleracionX = ACELERACION_NULA
		}

		// --------------------------------------------------------------------
		public function desplazarVerticalmente(direccion:Point):void {
			_aceleracionY = ACELERACION_GRAVITATORIA * direccion.y
		}
		// --------------------------------------------------------------------
		public function dejarDeDesplazarVerticalmente():void {
			_aceleracionY = ACELERACION_NULA
		}

		// --------------------------------------------------------------------
		private function actualizar():void
		{
			//_antesDeActualizar.notificar(calcularNuevaPosicion())
			if (_aceleracionX != 0 || _aceleracionY != 0)
				posicionar(calcularNuevaPosicion())
			//_despuesDeActualizar.notificar()
		}
		// --------------------------------------------------------------------
		private function calcularNuevaPosicion():Point
		{	
			var posicionOriginal:Point = _posicion.clone()

			// X(t) = Xi + Vi * dt + (0.5 * a * dt * dt)
			var dt:Number = API.reloj.delta
			var dX:Number = (0.5 * _aceleracionX * dt * dt)
			var dY:Number = (0.5 * _aceleracionY * dt * dt)
			var posicionFinal:Point = new Point(
				_posicion.x + dX,
				_posicion.y + dY
			)

			_velocidad = new Point(dX, dY)

			posicionarGrafico(posicionFinal)
			while (HitTest.ComplexHitTestObject(_mundo.grafico, _grafico))
			{
				posicionFinal.y -= dY / 5
				posicionarGrafico(posicionFinal)
			}

			posicionarGrafico(posicionFinal)
			while (HitTest.ComplexHitTestObject(_mundo.grafico, _grafico))
			{
				posicionFinal.x -= dX / 5
				posicionarGrafico(posicionFinal)
			}

			posicionarGrafico(posicionOriginal)

			return posicionFinal
		}
	}
}